<template>
  <div :class="{ 'anvil-code-table-container': true, reverse: pagePosition !== 'bottom' }">
    <el-table
      :data="tableData"
      class="anvil-code-table"
      border
      stripe
      scrollbar-always-on
      :row-key="rowKey"
      :highlight-current-row="highlightCurrentRow"
      :show-summary="isShowSummary"
      :max-height="maxHeight ? maxHeight : undefined"
      :span-method="handleSpanMethod"
      :summary-method="handleSummaryMethod"
      @selection-change="handleSelectionChange"
      @select="
        () => {
          select();
        }
      "
      @select-all="
        () => {
          selectAll();
        }
      "
      @row-click="
        () => {
          rowClick();
        }
      "
      @row-dblclick="
        () => {
          rowDblClick();
        }
      "
      @current-change="handleCurrentChange"
    >
      <el-table-column width="80" align="center" v-if="showButtons">
        <template #header="{}">
          <el-button icon="el-icon-plus" type="primary" circle @click="addColumn" :disabled="disabled" />
        </template>
        <template #default="scope">
          <div @mouseenter="handleHover(scope.$index)" @mouseleave="handleLeave(scope.$index)">
            <span v-if="!showBtns[scope.$index]">{{ scope.$index + 1 }}</span>
            <el-button v-if="showBtns[scope.$index]" icon="el-icon-delete" type="danger" circle @click="deleteColumn(scope.$index)" :disabled="disabled" />
          </div>
        </template>
      </el-table-column>
      <el-table-column type="selection" :selectable="selectableFunc" :reserve-selection="reserveSelection" width="50" align="center" v-if="showCheckbox" />
      <el-table-column type="index" label="序号" width="60" align="center" v-if="showIndex" />
      <template v-for="(column, index) in tableColumns" :key="index">
        <anvil-table-column
          v-if="column.children"
          :children="children.column"
          :columnSettingObject="column"
          :handleEditColumn="handleEditColumn"
          :getColumnParams="getColumnParams"
          :formData="formData"
        >
        </anvil-table-column>
        <el-table-column
          v-else-if="column.display"
          :label="column && column.label"
          :prop="column && column.prop"
          :width="column.columnWidth"
          :min-width="column.columnMinWidth ? column.columnMinWidth : 200"
          :fixed="column.fixed == '-' ? undefined : column.fixed"
          :show-overflow-tooltip="column.showTooltip"
          align="center"
        >
          <template #header="scope" v-if="column.columnEditable">
            <span>{{ scope.column.label }}</span>
            <el-button style="margin-left: 8px" icon="el-icon-edit" link @click="handleEditColumn(column, scope.$index)" />
          </template>
          <template #default="scope">
            <div :class="column.classNames ? column.classNames.join(' ') : ''">
              <custom-comp-item v-if="isProvideFormData(column.type)" v-model="scope.row[column.prop]" :item="column" :params="getColumnParams(column, scope)" :formData="formData" />
              <custom-comp-item v-else v-model="scope.row[column.prop]" :item="column" :params="getColumnParams(column, scope)" />
            </div>
          </template>
        </el-table-column>
      </template>
      <!-- <anvil-table-column :children="children.column" :column-setting-array="tableColumns">
        <template #header="{ scope, column }" v-if="column && column.columnEditable">
          <span>{{ scope.column.label }}</span>
          <el-button style="margin-left: 8px" icon="el-icon-edit" link @click="handleEditColumn(column, scope.$index)" />
        </template>
        <template #default="{ scope, column }">
          <div :class="column.className ? column.className : ''">
            <custom-comp-item v-if="isProvideFormData(column.type)" v-model="scope.row[column.prop]" :item="column" :params="getColumnParams(column, scope)" :formData="formData" />
            <custom-comp-item v-else v-model="scope.row[column.prop]" :item="column" :params="getColumnParams(column, scope)" />
          </div>
        </template>
      </anvil-table-column> -->
    </el-table>

    <el-dialog title="修改整列值" v-model="showEditCol" width="400">
      <el-input v-model="colEditStr" placeholder="请输入" />
      <template #footer>
        <dialog-footer @ok="submitEditCol" @cancel="cancelEdit" />
      </template>
    </el-dialog>

    <component
      :is="pagination"
      v-if="page && pageObj.total > 0"
      :total="pageObj.total"
      v-model:page="pageObj.pageNum"
      v-model:limit="pageObj.pageSize"
      layout="total,prev,pager,next,sizes,jumper"
      @pagination="
        () => {
          search();
        }
      "
    />
  </div>
</template>

<script>
import customCompItem from '../../views/form-render/customCompItem.vue';
import { customApiExecute, modelApiExecute, localApiExecute, getParamsWithMerge } from '../../utils/common-methods';
import { ElMessage, ElMessageBox } from 'element-plus';
import JsonPath from 'jsonpath';
import { h, nextTick } from 'vue';
import anvilPagination from '../anvilPagination/anvilPagination.vue';
import { provideFormData } from '../../utils/specialCompTypes';
import { pick, isEqual, xorBy } from 'lodash-es';

export default {
  name: 'AnvilTable',
  components: { customCompItem, anvilPagination },
  inject: ['getDataFromOthers'],
  props: {
    // 表单对象
    formData: {
      type: Object,
      default: () => {}
    },
    disabled: {
      type: Boolean,
      default: false
    },
    modelValue: {
      type: Object,
      default: () => {}
    },
    children: {
      type: Object,
      default: () => {}
    },
    prop: {
      type: String,
      default: ''
    },
    page: {
      type: Boolean,
      default: false
    },
    // 分页位置
    pagePosition: {
      type: String,
      default: 'bottom'
    },
    // 初始分页大小
    pageSize: {
      type: Number,
      default: 10
    },
    // 列表查询地址
    searchUrl: {
      type: String,
      default: ''
    },
    // 查询携带的请求体参数
    searchParams: {
      type: Object,
      default: () => {}
    },
    // 开启操作按钮
    showButtons: {
      type: Boolean,
      default: false
    },
    // 开启序号展示
    showIndex: {
      type: Boolean,
      default: false
    },
    // 开启checkbox
    showCheckbox: {
      type: Boolean,
      default: false
    },
    // 开启单选
    highlightCurrentRow: {
      type: Boolean,
      default: false
    },
    // 默认调用查询事件
    autoLoad: {
      type: Boolean,
      default: true
    },
    // 加载数据类型
    loadType: {
      type: String,
      default: ''
    },
    // 接口调用方式
    method: {
      type: String,
      default: 'post'
    },
    contentType: {
      type: String,
      default: 'formData'
    },
    jsonPath: {
      type: String,
      default: ''
    },
    maxHeight: {
      type: Number,
      default: 0
    },
    uniqFields: {
      type: String,
      default: ''
    },
    staticData: {
      type: Array,
      default: () => []
    },
    // 接口前置钩子函数标识
    hookBefore: {
      type: String,
      default: ''
    },
    // 接口后置钩子函数标识
    hookAfter: {
      type: String,
      default: ''
    },
    // 取消遮罩层加载
    noLoading: {
      type: Boolean,
      default: false
    },
    // 数据刷新后是否保留选项
    reserveSelection: {
      type: Boolean,
      default: false
    },
    // 行数据的 Key
    rowKey: {
      type: String,
      default: undefined
    },
    // 选择分页组件
    pagination: {
      type: String,
      default: 'anvilPagination'
    },
    // 行列合并函数
    spanMethod: {
      type: Function,
      default: () => {}
    },
    // 合计函数
    summaryMethod: {
      type: Function,
      default: undefined
    },
    // 多级表头函数
    multiHeaderMethod: {
      type: Function,
      default: undefined
    },
    select: {
      type: Function,
      default: () => {}
    },
    selectAll: {
      type: Function,
      default: () => {}
    },
    rowClick: {
      type: Function,
      default: () => {}
    },
    rowDblClick: {
      type: Function,
      default: () => {}
    },
    change: {
      type: Function,
      default: () => {}
    },
    selectableFunc: {
      type: Function,
      default: undefined
    }
  },
  data() {
    return {
      tableData: [],
      showDialog: false,
      curColumnData: {},
      curIndex: 0,
      diaglogType: 'add',
      showBtns: [],
      dynamicColumns: [],
      pageObj: {
        pageNum: 1,
        pageSize: this.pageSize,
        total: 0
      },
      selection: [],
      curSelect: {},
      colEditStr: '',
      showEditCol: false
    };
  },
  computed: {
    modelForm() {
      return { list: this.tableData };
    },
    isShowSummary() {
      return this.summaryMethod && typeof this.summaryMethod == 'function';
    },
    tableColumns() {
      if (this.multiHeaderMethod && typeof this.multiHeaderMethod == 'function') {
        const headerSettingArr = this.multiHeaderMethod();
        this.generateTableColumns(headerSettingArr);
        return headerSettingArr;
      } else {
        return this.children.column;
      }
    }
  },
  watch: {
    modelValue: {
      handler() {
        if (this.modelValue) {
          if (typeof this.modelValue == 'function') {
            this.tableData = this.modelValue();
          } else if (this.modelValue instanceof Array) {
            this.tableData = this.modelValue;
          }
        } else {
          this.tableData = [];
        }
        this.initDynamicColumns();
      },
      immediate: true,
      deep: true
    },
    tableData: {
      handler(newVal, oldVal) {
        this.$emit('update:modelValue', newVal);
        if (this.change && typeof this.change == 'function') {
          this.change(newVal);
        }
      },
      deep: true
    },
    // 目前外部值变化 影响内部值的只有disabled
    disabled: {
      handler(newVal) {
        this.setDynamicColsDisabled();
      },
      immediate: true
    },
    children: {
      handler(newVal) {},
      deep: true
    }
  },
  created() {
    if (this.dataFromOthers) {
      console.log('dataFromOthers', this.dataFromOthers());
    }

    this.initDynamicColumns();
  },
  mounted() {
    if (this.autoLoad) {
      this.search();
    }
  },
  methods: {
    addColumn() {
      // 平铺模式
      if (!this.tableData.length) {
        this.tableData = [{}];
        this.showBtns = [false];
        this.dynamicColumns = [
          {
            ...this.children,
            column: JSON.parse(JSON.stringify(this.children.column))
          }
        ];
      } else {
        this.tableData.push({});
        this.showBtns.push(false);
        this.dynamicColumns.push({
          ...this.children,
          column: JSON.parse(JSON.stringify(this.children.column))
        });
      }
    },
    deleteColumn(data) {
      let index = null;
      // 可以接收两种参数，对象或者序号index，对象会去属性中寻找index
      if (Object.prototype.toString.call(data) == '[object Object]') {
        index = data.index;
      } else if (typeof data == 'number') {
        index = data;
      }
      this.tableData.splice(index, 1);
      this.showBtns.splice(index, 1);
      if (this.dynamicColumns.length) {
        this.dynamicColumns.splice(index, 1);
      }
    },
    handleHover(index) {
      if (!this.disabled) {
        this.showBtns[index] = true;
        // this.$set(this.showBtns, index, true)
      }
    },
    handleLeave(index) {
      if (!this.disabled) {
        this.showBtns[index] = false;
        // this.$set(this.showBtns, index, false)
      }
    },
    // 对当前子表单内容进行校验
    validateForm() {
      const lines = [];
      // 表单模式
      // eslint-disable-next-line @typescript-eslint/no-this-alias
      let that = this;

      lines.push(that.$refs.valiFormDynamic.validate());
      console.log('lines', lines);
      return lines;
    },
    // 对子表单的渲染数据结构进行初始化
    initDynamicColumns() {
      this.dynamicColumns = [];
      if (this.tableData && this.tableData.length) {
        for (let i = 0; i < this.tableData.length; i++) {
          this.dynamicColumns.push({
            ...this.children
          });
        }
      }
      this.setDynamicColsDisabled();
    },
    // 接收disabled属性并传递到内部
    setDynamicColsDisabled() {
      this.dynamicColumns.map((dynCol, index) => {
        dynCol.column.map((child, idx) => {
          const { disabled } = child;
          // 如果子表单disabled为true，内部所有组件为disabled
          if (this.disabled) {
            this.dynamicColumns[index].column[idx]['disabled'] = this.disabled;
            // this.$set(this.dynamicColumns[index].column[idx], 'disabled', this.disabled)
          }
          // 否则按照组件自己的disabled值赋值
          else {
            this.dynamicColumns[index].column[idx]['disabled'] = disabled;
            // this.$set(this.dynamicColumns[index].column[idx], 'disabled', disabled)
          }
        });
      });
    },
    load(data) {
      if (!data instanceof Array) {
        ElMessage.error('请传入正确数据类型！');
        return;
      }
      this.tableData = data;
    },
    // 加载数据方法
    async search(query) {
      if (this.loadType.includes('url') && this.searchUrl) {
        const { pageNum, pageSize } = this.pageObj;

        const body = getParamsWithMerge(this, this.searchParams);

        let params = {
          pageNum,
          pageSize,
          ...this.mergeObjects(body, query)
        };

        params = this.operateHookBefore(params);

        console.log('表格查询参数', params);

        const callback = (res) => {
          try {
            const Res = this.operateHookAfter(res);
            if (this.page) {
              this.load(Res.data.list);
              this.pageObj.total = Res.data.total;
            } else {
              this.load(Res.data);
            }
          } catch (e) {
            console.log('表格数据解析失败', e);
          }
        };

        const config = {
          url: this.searchUrl,
          method: this.method,
          contentType: this.contentType,
          params,
          callback
        };

        switch (this.loadType) {
          case 'url':
            return customApiExecute(config, { noLoading: this.noLoading });
          case 'urlModel':
            return modelApiExecute(config, { noLoading: this.noLoading });
          case 'urlLocal':
            return localApiExecute(config, { noLoading: this.noLoading });
        }
      } else if (this.jsonPath) {
        if (this.getDataFromOthers && typeof this.getDataFromOthers == 'function' && this.getDataFromOthers()) {
          const data = JsonPath.query(this.getDataFromOthers(), this.jsonPath);
          if (data && data.length) {
            if (this.page) {
              this.load(data[0]);
              this.pageObj.total = data[0].length;
            } else {
              this.load(data[0]);
            }
          }
        }
      } else if (this.staticData && this.staticData.length) {
        this.load(this.staticData);
      }
    },
    // 提供的获取选中数据的方法
    getSelection() {
      return this.selection;
    },
    // getSelect() {
    //   return this.select;
    // },
    updateRow(data) {
      const { row, index } = data;
      this.tableData.splice(index, 1, row);
    },
    addRow(data) {
      // 添加时若需要重复性校验则进行校验
      if (this.uniqFields) {
        this.checkUniq(data);
      }
      if (Object.prototype.toString.call(data) == '[object Object]') {
        const filterData = this.filterNeedProperties(data);
        this.tableData.push(filterData);
      } else if (Object.prototype.toString.call(data) == '[object Array]') {
        const filterArr = data.map((item) => {
          return this.filterNeedProperties(item);
        });
        this.tableData.push(...filterArr);
      }
    },
    deleteRow(index) {
      this.tableData.splice(index, 1);
    },
    // 删除列表选中
    deleteSelection() {
      this.selection.map((item) => {
        const index = this.tableData.indexOf(item);
        this.tableData.splice(index, 1);
      });
      this.selection = [];
    },
    // 校验唯一标识
    checkUniq(data) {
      const uniqArr = this.uniqFields.split(',');
      // 记录需要校验的字段组成一个对象
      const uniqFleldObj = pick(data, uniqArr);

      if (Object.prototype.toString.call(data) == '[object Object]') {
        const isExist = this.tableData.find((item) => {
          const obj = pick(item, uniqArr);
          return isEqual(uniqFleldObj, obj);
        });
        if (isExist) {
          throw Error('表格已存在重复数据！');
        }
      } else if (Object.prototype.toString.call(data) == '[object Array]') {
        const xorArr = xorBy(data, this.tableData, ...uniqArr);
        if (xorArr && xorArr.length < data.length + this.tableData.length) {
          throw Error('表格已存在重复数据！');
        }
      }
    },
    // 过滤出表格需要的属性
    filterNeedProperties(obj) {
      let resObj = {};
      this.children.column.map((col) => {
        const { prop } = col;
        if (prop in obj) {
          resObj[prop] = obj[prop];
        }
      });
      console.log('filterObj', resObj);
      return resObj;
    },
    // 组件获取prams功能,这里需要把row、pageId都传进去
    getColumnParams(column, scope) {
      const { row, $index } = scope;
      const dictObj = this.getDicDataFromTable(column, row);
      const params = {
        scopeRow: {
          row,
          index: $index
        },
        pageId: this.$attrs.pageId,
        ...dictObj
      };

      if (dictObj) {
        this.watchRowData(column, scope, dictObj);
      }

      return params;
    },
    // 监听行中下拉框数据变化，向行数据中添加对象
    watchRowData(column, scope, dictObj) {
      const { row, $index } = scope;
      const { prop, type } = column;
      if (type == 'select') {
        if (scope.row[`watch${prop}`]) {
          console.log('已开启监听');
          return;
        } else {
          console.log('正在开启监听');
          scope.row[`watch${prop}`] = true;

          this.$watch(
            `tableData.${$index}.${prop}`,
            function (newV) {
              console.log('切换至新值', newV);
              const { dicData } = dictObj;
              scope.row[`${prop}Item`] = dicData.find((dic) => dic.dictValue == newV);
            },
            { deep: true }
          );
        }
      }
    },
    // 属于带dicData属性的字段的方法 下拉框/复选框组/单选框组
    getDicDataFromTable(column, row) {
      const { prop, type, dicData, dictFromScope, dictFromScopeField } = column;
      if (dicData && prop && row && dictFromScope && dictFromScopeField) {
        // 要获取动态字典数据的属性名
        if (row[dictFromScopeField] && row[dictFromScopeField].length) {
          // 默认带入第一个选项
          // row[prop] = row[dictFromScopeField][0].dictValue
          return {
            dicData: row[dictFromScopeField]
          };
        } else {
          return {};
        }
      }
    },
    handleSelectionChange(selectionArr) {
      this.selection = selectionArr;
    },
    handleCurrentChange(select) {
      this.selection = [select];
    },
    // 提供编辑整列数据的方法
    handleEditColumn(column, index) {
      this.curColumnData = column;
      this.colEditStr = '';
      this.showEditCol = true;
    },
    cancelEdit() {
      this.showEditCol = false;
    },
    submitEditCol() {
      const { prop } = this.curColumnData;
      this.tableData.map((item) => {
        item[prop] = this.colEditStr;
      });
      this.cancelEdit();
    },
    // 合并两个对象，若属性存在重复，则只取有值的
    mergeObjects(obj1, obj2) {
      const result = { ...obj1 };

      if (!obj2) {
        return result;
      }

      for (const key in obj2) {
        if (
          obj2[key] !== '' ||
          (Object.prototype.toString.call(obj2[key]) == '[object Array]' && obj2[key].length) ||
          (Object.prototype.toString.call(obj2[key]) == '[object Object]' && Object.keys(obj2[key]).length)
        ) {
          result[key] = obj2[key];
        }
      }

      return result;
    },
    // 接口调用执行前钩子
    operateHookBefore(data) {
      try {
        if (this.hookBefore) {
          const anvilCodeStore = this.useAnvilCodeStore();
          // 获取当前表单实例
          const { instance } = anvilCodeStore.getPageForm(this.$attrs.pageId);
          return instance[this.hookBefore](data);
        } else {
          return data;
        }
      } catch (e) {
        console.log('error!', e);
        return data;
      }
    },
    operateHookAfter(data) {
      try {
        if (this.hookAfter) {
          const anvilCodeStore = this.useAnvilCodeStore();
          // 获取当前表单实例
          const { instance } = anvilCodeStore.getPageForm(this.$attrs.pageId);
          return instance[this.hookAfter](data);
        } else {
          return data;
        }
      } catch (e) {
        console.log('error!', e);
        return data;
      }
    },
    // 根据组件类型判断是否提供formdata参数
    isProvideFormData(type) {
      const types = provideFormData;
      return types.indexOf(type) > -1;
    },
    handleSpanMethod(settings) {
      if (this.spanMethod && typeof this.spanMethod == 'function') {
        return this.spanMethod(this.tableData, settings);
      } else {
        return undefined;
      }
    },
    handleSummaryMethod(param) {
      if (this.summaryMethod && typeof this.summaryMethod == 'function') {
        return this.summaryMethod(param);
      } else {
        return undefined;
      }
    },
    generateTableColumns(list) {
      list.map((item) => {
        const { label, children, prop } = item;
        if (prop) {
          const comp = this.children.column.find((item) => item.prop == prop);
          if (comp) {
            for (let key in comp) {
              item[key] = comp[key];
            }
          }
        }
        if (children) {
          this.generateTableColumns(children);
        }
      });
    }
  }
};
</script>

<style lang="scss" scoped>
.anvil-code-table-container {
  display: flex;
  flex-direction: column;
}

.reverse {
  flex-direction: column-reverse;
}
</style>
